<?xml version="1.0" encoding="utf-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
        "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <link href="../Styles/sure3.css" rel="stylesheet" type="text/css"/>
    <link href="../Styles/base1.css" rel="stylesheet" type="text/css"/>
</head>

<body>
<div class="markdown-body entry-content" itemprop="text">
    <h1><a href="#ecmascript-6-简介"  class="anchor" id="user-content-ecmascript-6-简介">
       
    </a>ECMAScript 6 简介
    </h1>
    <p>ECMAScript 6.0（以下简称 ES6）是 JavaScript 语言的下一代标准，已经在 2015 年 6 月正式发布了。它的目标，是使得 JavaScript
        语言可以用来编写复杂的大型应用程序，成为企业级开发语言。</p>
    <h2><a href="#ecmascript-和-javascript-的关系"  class="anchor"
           id="user-content-ecmascript-和-javascript-的关系">
       
    </a>ECMAScript 和 JavaScript 的关系
    </h2>
    <p>一个常见的问题是，ECMAScript 和 JavaScript 到底是什么关系？</p>
    <p>要讲清楚这个问题，需要回顾历史。1996 年 11 月，JavaScript 的创造者 Netscape 公司，决定将 JavaScript 提交给国际标准化组织 ECMA，希望这种语言能够成为国际标准。次年，ECMA 发布
        262 号标准文件（ECMA-262）的第一版，规定了浏览器脚本语言的标准，并将这种语言称为 ECMAScript，这个版本就是 1.0 版。</p>
    <p>该标准从一开始就是针对 JavaScript 语言制定的，但是之所以不叫 JavaScript，有两个原因。一是商标，Java 是 Sun 公司的商标，根据授权协议，只有 Netscape 公司可以合法地使用
        JavaScript 这个名字，且 JavaScript 本身也已经被 Netscape 公司注册为商标。二是想体现这门语言的制定者是 ECMA，不是 Netscape，这样有利于保证这门语言的开放性和中立性。</p>
    <p>因此，ECMAScript 和 JavaScript 的关系是，前者是后者的规格，后者是前者的一种实现（另外的 ECMAScript 方言还有 Jscript 和
        ActionScript）。日常场合，这两个词是可以互换的。</p>
    <h2><a href="#es6-与-ecmascript-2015-的关系"  class="anchor"
           id="user-content-es6-与-ecmascript-2015-的关系">
       
    </a>ES6 与 ECMAScript 2015 的关系
    </h2>
    <p>ECMAScript 2015（简称 ES2015）这个词，也是经常可以看到的。它与 ES6 是什么关系呢？</p>
    <p>2011 年，ECMAScript 5.1 版发布后，就开始制定 6.0 版了。因此，ES6 这个词的原意，就是指 JavaScript 语言的下一个版本。</p>
    <p>但是，因为这个版本引入的语法功能太多，而且制定过程当中，还有很多组织和个人不断提交新功能。事情很快就变得清楚了，不可能在一个版本里面包括所有将要引入的功能。常规的做法是先发布 6.0 版，过一段时间再发 6.1 版，然后是
        6.2 版、6.3 版等等。</p>
    <p>
        但是，标准的制定者不想这样做。他们想让标准的升级成为常规流程：任何人在任何时候，都可以向标准委员会提交新语法的提案，然后标准委员会每个月开一次会，评估这些提案是否可以接受，需要哪些改进。如果经过多次会议以后，一个提案足够成熟了，就可以正式进入标准了。这就是说，标准的版本升级成为了一个不断滚动的流程，每个月都会有变动。</p>
    <p>标准委员会最终决定，标准在每年的 6 月份正式发布一次，作为当年的正式版本。接下来的时间，就在这个版本的基础上做改动，直到下一年的 6
        月份，草案就自然变成了新一年的版本。这样一来，就不需要以前的版本号了，只要用年份标记就可以了。</p>
    <p>ES6 的第一个版本，就这样在 2015 年 6 月发布了，正式名称就是《ECMAScript 2015 标准》（简称 ES2015）。2016 年 6 月，小幅修订的《ECMAScript 2016 标准》（简称
        ES2016）如期发布，这个版本可以看作是 ES6.1 版，因为两者的差异非常小（只新增了数组实例的<code>includes</code>方法和指数运算符），基本上是同一个标准。根据计划，2017 年 6 月发布
        ES2017 标准。</p>
    <p>因此，ES6 既是一个历史名词，也是一个泛指，含义是 5.1 版以后的 JavaScript 的下一代标准，涵盖了 ES2015、ES2016、ES2017 等等，而 ES2015
        则是正式名称，特指该年发布的正式版本的语言标准。本书中提到 ES6 的地方，一般是指 ES2015 标准，但有时也是泛指“下一代 JavaScript 语言”。</p>
    <h2><a href="#语法提案的批准流程"  class="anchor" id="user-content-语法提案的批准流程">
       
    </a>语法提案的批准流程
    </h2>
    <p>任何人都可以向标准委员会（又称 TC39 委员会）提案，要求修改语言标准。</p>
    <p>一种新的语法从提案到变成正式标准，需要经历五个阶段。每个阶段的变动都需要由 TC39 委员会批准。</p>
    <ul>
        <li>Stage 0 - Strawman（展示阶段）</li>
        <li>Stage 1 - Proposal（征求意见阶段）</li>
        <li>Stage 2 - Draft（草案阶段）</li>
        <li>Stage 3 - Candidate（候选人阶段）</li>
        <li>Stage 4 - Finished（定案阶段）</li>
    </ul>
    <p>一个提案只要能进入 Stage 2，就差不多肯定会包括在以后的正式标准里面。ECMAScript 当前的所有提案，可以在 TC39 的官方网站<a href="https://github.com/tc39/ecma262">Github.com/tc39/ecma262</a>查看。
    </p>
    <p>本书的写作目标之一，是跟踪 ECMAScript 语言的最新进展，介绍 5.1 版本以后所有的新语法。对于那些明确或很有希望，将要列入标准的新语法，都将予以介绍。</p>
    <h2><a href="#ecmascript-的历史"  class="anchor" id="user-content-ecmascript-的历史">
        
    </a>ECMAScript 的历史
    </h2>
    <p>ES6 从开始制定到最后发布，整整用了 15 年。</p>
    <p>前面提到，ECMAScript 1.0 是 1997 年发布的，接下来的两年，连续发布了 ECMAScript 2.0（1998 年 6 月）和 ECMAScript 3.0（1999 年 12 月）。3.0
        版是一个巨大的成功，在业界得到广泛支持，成为通行标准，奠定了 JavaScript 语言的基本语法，以后的版本完全继承。直到今天，初学者一开始学习 JavaScript，其实就是在学 3.0 版的语法。</p>
    <p>2000 年，ECMAScript 4.0 开始酝酿。这个版本最后没有通过，但是它的大部分内容被 ES6 继承了。因此，ES6 制定的起点其实是 2000 年。</p>
    <p>为什么 ES4 没有通过呢？因为这个版本太激进了，对 ES3 做了彻底升级，导致标准委员会的一些成员不愿意接受。ECMA 的第 39 号技术专家委员会（Technical Committee 39，简称 TC39）负责制订
        ECMAScript 标准，成员包括 Microsoft、Mozilla、Google 等大公司。</p>
    <p>2007 年 10 月，ECMAScript 4.0 版草案发布，本来预计次年 8 月发布正式版本。但是，各方对于是否通过这个标准，发生了严重分歧。以 Yahoo、Microsoft、Google 为首的大公司，反对
        JavaScript 的大幅升级，主张小幅改动；以 JavaScript 创造者 Brendan Eich 为首的 Mozilla 公司，则坚持当前的草案。</p>
    <p>2008 年 7 月，由于对于下一个版本应该包括哪些功能，各方分歧太大，争论过于激烈，ECMA 开会决定，中止 ECMAScript 4.0 的开发，将其中涉及现有功能改善的一小部分，发布为 ECMAScript
        3.1，而将其他激进的设想扩大范围，放入以后的版本，由于会议的气氛，该版本的项目代号起名为 Harmony（和谐）。会后不久，ECMAScript 3.1 就改名为 ECMAScript 5。</p>
    <p>2009 年 12 月，ECMAScript 5.0 版正式发布。Harmony 项目则一分为二，一些较为可行的设想定名为 JavaScript.next 继续开发，后来演变成 ECMAScript
        6；一些不是很成熟的设想，则被视为 JavaScript.next.next，在更远的将来再考虑推出。TC39 委员会的总体考虑是，ES5 与 ES3 基本保持兼容，较大的语法修正和新功能加入，将由
        JavaScript.next 完成。当时，JavaScript.next 指的是 ES6，第六版发布以后，就指 ES7。TC39 的判断是，ES5 会在 2013 年的年中成为 JavaScript
        开发的主流标准，并在此后五年中一直保持这个位置。</p>
    <p>2011 年 6 月，ECMAscript 5.1 版发布，并且成为 ISO 国际标准（ISO/IEC 16262:2011）。</p>
    <p>2013 年 3 月，ECMAScript 6 草案冻结，不再添加新功能。新的功能设想将被放到 ECMAScript 7。</p>
    <p>2013 年 12 月，ECMAScript 6 草案发布。然后是 12 个月的讨论期，听取各方反馈。</p>
    <p>2015 年 6 月，ECMAScript 6 正式通过，成为国际标准。从 2000 年算起，这时已经过去了 15 年。</p>
    <h2><a href="#部署进度"  class="anchor" id="user-content-部署进度">
       
    </a>部署进度
    </h2>
    <p>各大浏览器的最新版本，对 ES6 的支持可以查看<a href="https://kangax.github.io/es5-compat-table/es6/">kangax.github.io/es5-compat-table/es6/</a>。随着时间的推移，支持度已经越来越高了，超过
        90%的 ES6 语法特性都实现了。</p>
    <p>Node 是 JavaScript 的服务器运行环境（runtime）。它对 ES6 的支持度更高。除了那些默认打开的功能，还有一些语法功能已经实现了，但是默认没有打开。使用下面的命令，可以查看 Node 已经实现的 ES6
        特性。</p>
    <div class="highlight highlight-source-shell">
        <pre>$ node --v8-options <span class="pl-k">|</span> grep harmony</pre>
    </div>
    <p>上面命令的输出结果，会因为版本的不同而有所不同。</p>
    <p>我写了一个工具 <a href="https://github.com/ruanyf/es-checker">ES-Checker</a>，用来检查各种运行环境对 ES6 的支持情况。访问<a
            href="http://ruanyf.github.io/es-checker">ruanyf.github.io/es-checker</a>，可以看到您的浏览器支持 ES6
        的程度。运行下面的命令，可以查看你正在使用的 Node 环境对 ES6 的支持程度。</p>
    <div class="highlight highlight-source-shell"><pre>$ npm install -g es-checker
$ es-checker

=========================================
Passes 24 feature Dectations
Your runtime supports 57% of ECMAScript 6
=========================================</pre>
    </div>
    <h2><a href="#babel-转码器"  class="anchor" id="user-content-babel-转码器">
        
    </a>Babel 转码器
    </h2>
    <p><a href="https://babeljs.io/">Babel</a> 是一个广泛使用的 ES6 转码器，可以将 ES6 代码转为 ES5 代码，从而在现有环境执行。这意味着，你可以用 ES6
        的方式编写程序，又不用担心现有环境是否支持。下面是一个例子。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-c"><span class="pl-c">//</span> 转码前</span>
<span class="pl-smi">input</span>.<span class="pl-en">map</span>(<span class="pl-smi">item</span> <span class="pl-k">=&gt;</span> item <span
                class="pl-k">+</span> <span class="pl-c1">1</span>);

<span class="pl-c"><span class="pl-c">//</span> 转码后</span>
<span class="pl-smi">input</span>.<span class="pl-en">map</span>(<span class="pl-k">function</span> (<span
                class="pl-smi">item</span>) {
  <span class="pl-k">return</span> item <span class="pl-k">+</span> <span class="pl-c1">1</span>;
});</pre>
    </div>
    <p>上面的原始代码用了箭头函数，Babel 将其转为普通函数，就能在不支持箭头函数的 JavaScript 环境执行了。</p>
    <h3><a href="#配置文件babelrc"  class="anchor" id="user-content-配置文件babelrc">
        
    </a>配置文件<code>.babelrc</code></h3>
    <p>Babel 的配置文件是<code>.babelrc</code>，存放在项目的根目录下。使用 Babel 的第一步，就是配置这个文件。</p>
    <p>该文件用来设置转码规则和插件，基本格式如下。</p>
    <div class="highlight highlight-source-js"><pre>{
  <span class="pl-s"><span class="pl-pds">"</span>presets<span class="pl-pds">"</span></span><span class="pl-k">:</span> [],
  <span class="pl-s"><span class="pl-pds">"</span>plugins<span class="pl-pds">"</span></span><span class="pl-k">:</span> []
}</pre>
    </div>
    <p><code>presets</code>字段设定转码规则，官方提供以下的规则集，你可以根据需要安装。</p>
    <div class="highlight highlight-source-shell"><pre><span class="pl-c"><span class="pl-c">#</span> 最新转码规则</span>
$ npm install --save-dev babel-preset-latest

<span class="pl-c"><span class="pl-c">#</span> react 转码规则</span>
$ npm install --save-dev babel-preset-react

<span class="pl-c"><span class="pl-c">#</span> 不同阶段语法提案的转码规则（共有4个阶段），选装一个</span>
$ npm install --save-dev babel-preset-stage-0
$ npm install --save-dev babel-preset-stage-1
$ npm install --save-dev babel-preset-stage-2
$ npm install --save-dev babel-preset-stage-3</pre>
    </div>
    <p>然后，将这些规则加入<code>.babelrc</code>。</p>
    <div class="highlight highlight-source-js"><pre>  {
    <span class="pl-s"><span class="pl-pds">"</span>presets<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> [
      <span class="pl-s"><span class="pl-pds">"</span>latest<span class="pl-pds">"</span></span>,
      <span class="pl-s"><span class="pl-pds">"</span>react<span class="pl-pds">"</span></span>,
      <span class="pl-s"><span class="pl-pds">"</span>stage-2<span class="pl-pds">"</span></span>
    ],
    <span class="pl-s"><span class="pl-pds">"</span>plugins<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> []
  }</pre>
    </div>
    <p>注意，以下所有 Babel 工具和模块的使用，都必须先写好<code>.babelrc</code>。</p>
    <h3><a href="#命令行转码babel-cli"  class="anchor" id="user-content-命令行转码babel-cli">
        
    </a>命令行转码<code>babel-cli</code></h3>
    <p>Babel 提供<code>babel-cli</code>工具，用于命令行转码。</p>
    <p>它的安装命令如下。</p>
    <div class="highlight highlight-source-shell">
        <pre>$ npm install --global babel-cli</pre>
    </div>
    <p>基本用法如下。</p>
    <div class="highlight highlight-source-shell"><pre><span class="pl-c"><span class="pl-c">#</span> 转码结果输出到标准输出</span>
$ babel example.js

<span class="pl-c"><span class="pl-c">#</span> 转码结果写入一个文件</span>
<span class="pl-c"><span class="pl-c">#</span> --out-file 或 -o 参数指定输出文件</span>
$ babel example.js --out-file compiled.js
<span class="pl-c"><span class="pl-c">#</span> 或者</span>
$ babel example.js -o compiled.js

<span class="pl-c"><span class="pl-c">#</span> 整个目录转码</span>
<span class="pl-c"><span class="pl-c">#</span> --out-dir 或 -d 参数指定输出目录</span>
$ babel src --out-dir lib
<span class="pl-c"><span class="pl-c">#</span> 或者</span>
$ babel src -d lib

<span class="pl-c"><span class="pl-c">#</span> -s 参数生成source map文件</span>
$ babel src -d lib -s</pre>
    </div>
    <p>上面代码是在全局环境下，进行 Babel 转码。这意味着，如果项目要运行，全局环境必须有 Babel，也就是说项目产生了对环境的依赖。另一方面，这样做也无法支持不同项目使用不同版本的 Babel。</p>
    <p>一个解决办法是将<code>babel-cli</code>安装在项目之中。</p>
    <div class="highlight highlight-source-shell"><pre><span class="pl-c"><span class="pl-c">#</span> 安装</span>
$ npm install --save-dev babel-cli</pre>
    </div>
    <p>然后，改写<code>package.json</code>。</p>
    <div class="highlight highlight-source-js"><pre>{
  <span class="pl-c"><span class="pl-c">//</span> ...</span>
  <span class="pl-s"><span class="pl-pds">"</span>devDependencies<span class="pl-pds">"</span></span><span class="pl-k">:</span> {
    <span class="pl-s"><span class="pl-pds">"</span>babel-cli<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">"</span>^6.0.0<span
                class="pl-pds">"</span></span>
  },
  <span class="pl-s"><span class="pl-pds">"</span>scripts<span class="pl-pds">"</span></span><span class="pl-k">:</span> {
    <span class="pl-s"><span class="pl-pds">"</span>build<span class="pl-pds">"</span></span><span class="pl-k">:</span> <span
                class="pl-s"><span class="pl-pds">"</span>babel src -d lib<span class="pl-pds">"</span></span>
  },
}</pre>
    </div>
    <p>转码的时候，就执行下面的命令。</p>
    <div class="highlight highlight-source-js">
        <pre>$ npm run build</pre>
    </div>
    <h3><a href="#babel-node"  class="anchor" id="user-content-babel-node">
        
    </a>babel-node
    </h3>
    <p><code>babel-cli</code>工具自带一个<code>babel-node</code>命令，提供一个支持 ES6 的 REPL 环境。它支持 Node 的 REPL 环境的所有功能，而且可以直接运行 ES6
        代码。</p>
    <p>它不用单独安装，而是随<code>babel-cli</code>一起安装。然后，执行<code>babel-node</code>就进入 REPL 环境。</p>
    <div class="highlight highlight-source-shell"><pre>$ babel-node
<span class="pl-k">&gt;</span> (x =<span class="pl-k">&gt;</span> x <span class="pl-k">*</span> 2)(1)
2</pre>
    </div>
    <p><code>babel-node</code>命令可以直接运行 ES6 脚本。将上面的代码放入脚本文件<code>es6.js</code>，然后直接运行。</p>
    <div class="highlight highlight-source-shell"><pre>$ babel-node es6.js
2</pre>
    </div>
    <p><code>babel-node</code>也可以安装在项目中。</p>
    <div class="highlight highlight-source-shell">
        <pre>$ npm install --save-dev babel-cli</pre>
    </div>
    <p>然后，改写<code>package.json</code>。</p>
    <div class="highlight highlight-source-js"><pre>{
  <span class="pl-s"><span class="pl-pds">"</span>scripts<span class="pl-pds">"</span></span><span class="pl-k">:</span> {
    <span class="pl-s"><span class="pl-pds">"</span>script-name<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">"</span>babel-node script.js<span
                class="pl-pds">"</span></span>
  }
}</pre>
    </div>
    <p>上面代码中，使用<code>babel-node</code>替代<code>node</code>，这样<code>script.js</code>本身就不用做任何转码处理。</p>
    <h3><a href="#babel-register"  class="anchor" id="user-content-babel-register">
        
    </a>babel-register
    </h3>
    <p>
        <code>babel-register</code>模块改写<code>require</code>命令，为它加上一个钩子。此后，每当使用<code>require</code>加载<code>.js</code>、<code>.jsx</code>、<code>.es</code>和<code>.es6</code>后缀名的文件，就会先用
        Babel 进行转码。</p>
    <div class="highlight highlight-source-shell">
        <pre>$ npm install --save-dev babel-register</pre>
    </div>
    <p>使用时，必须首先加载<code>babel-register</code>。</p>
    <div class="highlight highlight-source-shell"><pre>require(<span class="pl-s"><span class="pl-pds">"</span>babel-register<span
            class="pl-pds">"</span></span>)<span class="pl-k">;</span>
require(<span class="pl-s"><span class="pl-pds">"</span>./index.js<span class="pl-pds">"</span></span>)<span
                class="pl-k">;</span></pre>
    </div>
    <p>然后，就不需要手动对<code>index.js</code>转码了。</p>
    <p>需要注意的是，<code>babel-register</code>只会对<code>require</code>命令加载的文件转码，而不会对当前文件转码。另外，由于它是实时转码，所以只适合在开发环境使用。</p>
    <h3><a href="#babel-core"  class="anchor" id="user-content-babel-core">
        
    </a>babel-core
    </h3>
    <p>如果某些代码需要调用 Babel 的 API 进行转码，就要使用<code>babel-core</code>模块。</p>
    <p>安装命令如下。</p>
    <div class="highlight highlight-source-shell">
        <pre>$ npm install babel-core --save</pre>
    </div>
    <p>然后，在项目中就可以调用<code>babel-core</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> babel <span
            class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">'</span>babel-core<span
            class="pl-pds">'</span></span>);

<span class="pl-c"><span class="pl-c">//</span> 字符串转码</span>
<span class="pl-smi">babel</span>.<span class="pl-en">transform</span>(<span class="pl-s"><span class="pl-pds">'</span>code();<span
                class="pl-pds">'</span></span>, options);
<span class="pl-c"><span class="pl-c">//</span> =&gt; { code, map, ast }</span>

<span class="pl-c"><span class="pl-c">//</span> 文件转码（异步）</span>
<span class="pl-smi">babel</span>.<span class="pl-en">transformFile</span>(<span class="pl-s"><span
                class="pl-pds">'</span>filename.js<span class="pl-pds">'</span></span>, options, <span class="pl-k">function</span>(<span
                class="pl-smi">err</span>, <span class="pl-smi">result</span>) {
  result; <span class="pl-c"><span class="pl-c">//</span> =&gt; { code, map, ast }</span>
});

<span class="pl-c"><span class="pl-c">//</span> 文件转码（同步）</span>
<span class="pl-smi">babel</span>.<span class="pl-en">transformFileSync</span>(<span class="pl-s"><span
                class="pl-pds">'</span>filename.js<span class="pl-pds">'</span></span>, options);
<span class="pl-c"><span class="pl-c">//</span> =&gt; { code, map, ast }</span>

<span class="pl-c"><span class="pl-c">//</span> Babel AST转码</span>
<span class="pl-smi">babel</span>.<span class="pl-en">transformFromAst</span>(ast, code, options);
<span class="pl-c"><span class="pl-c">//</span> =&gt; { code, map, ast }</span></pre>
    </div>
    <p>配置对象<code>options</code>，可以参看官方文档<a href="http://babeljs.io/docs/usage/options/">http://babeljs.io/docs/usage/options/</a>。
    </p>
    <p>下面是一个例子。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> es6Code <span
            class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">'</span>let x = n =&gt; n + 1<span
            class="pl-pds">'</span></span>;
<span class="pl-k">var</span> es5Code <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span
                class="pl-pds">'</span>babel-core<span class="pl-pds">'</span></span>)
  .<span class="pl-en">transform</span>(es6Code, {
    presets<span class="pl-k">:</span> [<span class="pl-s"><span class="pl-pds">'</span>latest<span
                class="pl-pds">'</span></span>]
  })
  .<span class="pl-c1">code</span>;
<span class="pl-c"><span
        class="pl-c">//</span> '"use strict";\n\nvar x = function x(n) {\n  return n + 1;\n};'</span></pre>
    </div>
    <p>上面代码中，<code>transform</code>方法的第一个参数是一个字符串，表示需要被转换的 ES6 代码，第二个参数是转换的配置对象。</p>
    <h3><a href="#babel-polyfill"  class="anchor" id="user-content-babel-polyfill">
        
    </a>babel-polyfill
    </h3>
    <p>Babel 默认只转换新的 JavaScript 句法（syntax），而不转换新的
        API，比如<code>Iterator</code>、<code>Generator</code>、<code>Set</code>、<code>Maps</code>、<code>Proxy</code>、<code>Reflect</code>、<code>Symbol</code>、<code>Promise</code>等全局对象，以及一些定义在全局对象上的方法（比如<code>Object.assign</code>）都不会转码。
    </p>
    <p>举例来说，ES6 在<code>Array</code>对象上新增了<code>Array.from</code>方法。Babel
        就不会转码这个方法。如果想让这个方法运行，必须使用<code>babel-polyfill</code>，为当前环境提供一个垫片。</p>
    <p>安装命令如下。</p>
    <div class="highlight highlight-source-shell">
        <pre>$ npm install --save babel-polyfill</pre>
    </div>
    <p>然后，在脚本头部，加入如下一行代码。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">import</span> <span class="pl-s"><span
            class="pl-pds">'</span>babel-polyfill<span class="pl-pds">'</span></span>;
<span class="pl-c"><span class="pl-c">//</span> 或者</span>
<span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">'</span>babel-polyfill<span
                class="pl-pds">'</span></span>);</pre>
    </div>
    <p>Babel 默认不转码的 API 非常多，详细清单可以查看<code>babel-plugin-transform-runtime</code>模块的<a
            href="https://github.com/babel/babel/blob/master/packages/babel-plugin-transform-runtime/src/definitions.js">definitions.js</a>文件。
    </p>
    <h3><a href="#浏览器环境"  class="anchor" id="user-content-浏览器环境">
        
    </a>浏览器环境
    </h3>
    <p>Babel 也可以用于浏览器环境。但是，从 Babel 6.0 开始，不再直接提供浏览器版本，而是要用构建工具构建出来。如果你没有或不想使用构建工具，可以使用<a
            href="https://github.com/Daniel15/babel-standalone">babel-standalone</a>模块提供的浏览器版本，将其插入网页。</p>
    <div class="highlight highlight-text-html-basic"><pre>&lt;<span class="pl-ent">script</span> <span
            class="pl-e">src</span>=<span class="pl-s"><span class="pl-pds">"</span>https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.4.4/babel.min.js<span
            class="pl-pds">"</span></span>&gt;&lt;/<span class="pl-ent">script</span>&gt;
&lt;<span class="pl-ent">script</span> <span class="pl-e">type</span>=<span class="pl-s"><span class="pl-pds">"</span>text/babel<span
                class="pl-pds">"</span></span>&gt;<span class="pl-s1"></span>
<span class="pl-s1"><span class="pl-c"><span class="pl-c">//</span> Your ES6 code</span></span>
<span class="pl-s1"></span><span class="pl-s1">&lt;</span>/<span class="pl-ent">script</span>&gt;</pre>
    </div>
    <p>注意，网页实时将 ES6 代码转为 ES5，对性能会有影响。生产环境需要加载已经转码完成的脚本。</p>
    <p>下面是如何将代码打包成浏览器可以使用的脚本，以<code>Babel</code>配合<code>Browserify</code>为例。首先，安装<code>babelify</code>模块。</p>
    <div class="highlight highlight-source-shell">
        <pre>$ npm install --save-dev babelify babel-preset-latest</pre>
    </div>
    <p>然后，再用命令行转换 ES6 脚本。</p>
    <div class="highlight highlight-source-shell"><pre>$  browserify script.js -o bundle.js \
  -t [ babelify --presets [ latest ] ]</pre>
    </div>
    <p>上面代码将 ES6 脚本<code>script.js</code>，转为<code>bundle.js</code>，浏览器直接加载后者就可以了。</p>
    <p>在<code>package.json</code>设置下面的代码，就不用每次命令行都输入参数了。</p>
    <div class="highlight highlight-source-js"><pre>{
  <span class="pl-s"><span class="pl-pds">"</span>browserify<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> {
    <span class="pl-s"><span class="pl-pds">"</span>transform<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> [[<span class="pl-s"><span class="pl-pds">"</span>babelify<span
                class="pl-pds">"</span></span>, { <span class="pl-s"><span class="pl-pds">"</span>presets<span
                class="pl-pds">"</span></span><span class="pl-k">:</span> [<span class="pl-s"><span
                class="pl-pds">"</span>latest<span class="pl-pds">"</span></span>] }]]
  }
}</pre>
    </div>
    <h3><a href="#在线转换"  class="anchor" id="user-content-在线转换">
        
    </a>在线转换
    </h3>
    <p>Babel 提供一个<a href="https://babeljs.io/repl/">REPL 在线编译器</a>，可以在线将 ES6 代码转为 ES5 代码。转换后的代码，可以直接作为 ES5 代码插入网页运行。</p>
    <h3><a href="#与其他工具的配合"  class="anchor" id="user-content-与其他工具的配合">
        
    </a>与其他工具的配合
    </h3>
    <p>许多工具需要 Babel 进行前置转码，这里举两个例子：ESLint 和 Mocha。</p>
    <p>ESLint 用于静态检查代码的语法和风格，安装命令如下。</p>
    <div class="highlight highlight-source-shell">
        <pre>$ npm install --save-dev eslint babel-eslint</pre>
    </div>
    <p>然后，在项目根目录下，新建一个配置文件<code>.eslintrc</code>，在其中加入<code>parser</code>字段。</p>
    <div class="highlight highlight-source-js"><pre>{
  <span class="pl-s"><span class="pl-pds">"</span>parser<span class="pl-pds">"</span></span><span class="pl-k">:</span> <span
                class="pl-s"><span class="pl-pds">"</span>babel-eslint<span class="pl-pds">"</span></span>,
  <span class="pl-s"><span class="pl-pds">"</span>rules<span class="pl-pds">"</span></span><span class="pl-k">:</span> {
    <span class="pl-k">...</span>
  }
}</pre>
    </div>
    <p>再在<code>package.json</code>之中，加入相应的<code>scripts</code>脚本。</p>
    <div class="highlight highlight-source-js"><pre>  {
    <span class="pl-s"><span class="pl-pds">"</span>name<span class="pl-pds">"</span></span><span class="pl-k">:</span> <span
                class="pl-s"><span class="pl-pds">"</span>my-module<span class="pl-pds">"</span></span>,
    <span class="pl-s"><span class="pl-pds">"</span>scripts<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> {
      <span class="pl-s"><span class="pl-pds">"</span>lint<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">"</span>eslint my-files.js<span
                class="pl-pds">"</span></span>
    },
    <span class="pl-s"><span class="pl-pds">"</span>devDependencies<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> {
      <span class="pl-s"><span class="pl-pds">"</span>babel-eslint<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">"</span>...<span
                class="pl-pds">"</span></span>,
      <span class="pl-s"><span class="pl-pds">"</span>eslint<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">"</span>...<span
                class="pl-pds">"</span></span>
    }
  }</pre>
    </div>
    <p>Mocha 则是一个测试框架，如果需要执行使用 ES6 语法的测试脚本，可以修改<code>package.json</code>的<code>scripts.test</code>。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-s"><span class="pl-pds">"</span>scripts<span
            class="pl-pds">"</span></span><span class="pl-k">:</span> {
  <span class="pl-s"><span class="pl-pds">"</span>test<span class="pl-pds">"</span></span><span
                class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">"</span>mocha --ui qunit --compilers js:babel-core/register<span
                class="pl-pds">"</span></span>
}</pre>
    </div>
    <p>上面命令中，<code>--compilers</code>参数指定脚本的转码器，规定后缀名为<code>js</code>的文件，都需要使用<code>babel-core/register</code>先转码。</p>
    <h2><a href="#traceur-转码器"  class="anchor" id="user-content-traceur-转码器">
        
    </a>Traceur 转码器
    </h2>
    <p>Google 公司的<a href="https://github.com/google/traceur-compiler">Traceur</a>转码器，也可以将 ES6 代码转为 ES5 代码。</p>
    <h3><a href="#直接插入网页"  class="anchor" id="user-content-直接插入网页">
        
    </a>直接插入网页
    </h3>
    <p>Traceur 允许将 ES6 代码直接插入网页。首先，必须在网页头部加载 Traceur 库文件。</p>
    <div class="highlight highlight-text-html-basic"><pre>&lt;<span class="pl-ent">script</span> <span
            class="pl-e">src</span>=<span class="pl-s"><span class="pl-pds">"</span>https://google.github.io/traceur-compiler/bin/traceur.js<span
            class="pl-pds">"</span></span>&gt;&lt;/<span class="pl-ent">script</span>&gt;
&lt;<span class="pl-ent">script</span> <span class="pl-e">src</span>=<span class="pl-s"><span class="pl-pds">"</span>https://google.github.io/traceur-compiler/bin/BrowserSystem.js<span
                class="pl-pds">"</span></span>&gt;&lt;/<span class="pl-ent">script</span>&gt;
&lt;<span class="pl-ent">script</span> <span class="pl-e">src</span>=<span class="pl-s"><span class="pl-pds">"</span>https://google.github.io/traceur-compiler/src/bootstrap.js<span
                class="pl-pds">"</span></span>&gt;&lt;/<span class="pl-ent">script</span>&gt;
&lt;<span class="pl-ent">script</span> <span class="pl-e">type</span>=<span class="pl-s"><span class="pl-pds">"</span>module<span
                class="pl-pds">"</span></span>&gt;<span class="pl-s1"></span>
<span class="pl-s1">  <span class="pl-k">import</span> <span class="pl-s"><span class="pl-pds">'</span>./Greeter.js<span
        class="pl-pds">'</span></span>;</span>
<span class="pl-s1"></span><span class="pl-s1">&lt;</span>/<span class="pl-ent">script</span>&gt;</pre>
    </div>
    <p>上面代码中，一共有 4 个<code>script</code>标签。第一个是加载 Traceur 的库文件，第二个和第三个是将这个库文件用于浏览器环境，第四个则是加载用户脚本，这个脚本里面可以使用 ES6 代码。</p>
    <p>注意，第四个<code>script</code>标签的<code>type</code>属性的值是<code>module</code>，而不是<code>text/javascript</code>。这是 Traceur
        编译器识别 ES6 代码的标志，编译器会自动将所有<code>type=module</code>的代码编译为 ES5，然后再交给浏览器执行。</p>
    <p>除了引用外部 ES6 脚本，也可以直接在网页中放置 ES6 代码。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">&lt;</span>script type<span class="pl-k">=</span><span
            class="pl-s"><span class="pl-pds">"</span>module<span class="pl-pds">"</span></span><span
            class="pl-k">&gt;</span>
  <span class="pl-k">class</span> <span class="pl-en">Calc</span> {
    <span class="pl-en">constructor</span>() {
      <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>Calc constructor<span
                class="pl-pds">'</span></span>);
    }
    <span class="pl-en">add</span>(<span class="pl-smi">a</span>, <span class="pl-smi">b</span>) {
      <span class="pl-k">return</span> a <span class="pl-k">+</span> b;
    }
  }

  <span class="pl-k">var</span> c <span class="pl-k">=</span> <span class="pl-k">new</span> <span
                class="pl-en">Calc</span>();
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-smi">c</span>.<span class="pl-c1">add</span>(<span
                class="pl-c1">4</span>,<span class="pl-c1">5</span>));
<span class="pl-k">&lt;</span><span class="pl-k">/</span>script<span class="pl-k">&gt;</span></pre>
    </div>
    <p>正常情况下，上面代码会在控制台打印出<code>9</code>。</p>
    <p>如果想对 Traceur 的行为有精确控制，可以采用下面参数配置的写法。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">&lt;</span>script<span class="pl-k">&gt;</span>
  <span class="pl-c"><span class="pl-c">//</span> Create the System object</span>
  <span class="pl-c1">window</span>.<span class="pl-smi">System</span> <span class="pl-k">=</span> <span class="pl-k">new</span> <span
                class="pl-en">traceur.runtime.BrowserTraceurLoader</span>();
  <span class="pl-c"><span class="pl-c">//</span> Set some experimental options</span>
  <span class="pl-k">var</span> metadata <span class="pl-k">=</span> {
    traceurOptions<span class="pl-k">:</span> {
      experimental<span class="pl-k">:</span> <span class="pl-c1">true</span>,
      properTailCalls<span class="pl-k">:</span> <span class="pl-c1">true</span>,
      symbols<span class="pl-k">:</span> <span class="pl-c1">true</span>,
      arrayComprehension<span class="pl-k">:</span> <span class="pl-c1">true</span>,
      asyncFunctions<span class="pl-k">:</span> <span class="pl-c1">true</span>,
      asyncGenerators<span class="pl-k">:</span> exponentiation,
      forOn<span class="pl-k">:</span> <span class="pl-c1">true</span>,
      generatorComprehension<span class="pl-k">:</span> <span class="pl-c1">true</span>
    }
  };
  <span class="pl-c"><span class="pl-c">//</span> Load your module</span>
  <span class="pl-smi">System</span>.<span class="pl-en">import</span>(<span class="pl-s"><span class="pl-pds">'</span>./myModule.js<span
                class="pl-pds">'</span></span>, {metadata<span class="pl-k">:</span> metadata}).<span class="pl-en">catch</span>(<span
                class="pl-k">function</span>(<span class="pl-smi">ex</span>) {
    <span class="pl-en">console</span>.<span class="pl-c1">error</span>(<span class="pl-s"><span class="pl-pds">'</span>Import failed<span
                class="pl-pds">'</span></span>, <span class="pl-smi">ex</span>.<span class="pl-smi">stack</span> <span
                class="pl-k">||</span> ex);
  });
<span class="pl-k">&lt;</span><span class="pl-k">/</span>script<span class="pl-k">&gt;</span></pre>
    </div>
    <p>上面代码中，首先生成 Traceur 的全局对象<code>window.System</code>，然后<code>System.import</code>方法可以用来加载
        ES6。加载的时候，需要传入一个配置对象<code>metadata</code>，该对象的<code>traceurOptions</code>属性可以配置支持 ES6 功能。如果设为<code>experimental:
            true</code>，就表示除了 ES6 以外，还支持一些实验性的新功能。</p>
    <h3><a href="#在线转换-1"  class="anchor" id="user-content-在线转换-1">
        
    </a>在线转换
    </h3>
    <p>Traceur 也提供一个<a href="http://google.github.io/traceur-compiler/demo/repl.html">在线编译器</a>，可以在线将 ES6 代码转为 ES5
        代码。转换后的代码，可以直接作为 ES5 代码插入网页运行。</p>
    <p>上面的例子转为 ES5 代码运行，就是下面这个样子。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">&lt;</span>script src<span
            class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>https://google.github.io/traceur-compiler/bin/traceur.js<span
            class="pl-pds">"</span></span><span class="pl-k">&gt;&lt;</span><span class="pl-k">/</span>script<span
            class="pl-k">&gt;</span>
<span class="pl-k">&lt;</span>script src<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>https://google.github.io/traceur-compiler/bin/BrowserSystem.js<span
                class="pl-pds">"</span></span><span class="pl-k">&gt;&lt;</span><span class="pl-k">/</span>script<span
                class="pl-k">&gt;</span>
<span class="pl-k">&lt;</span>script src<span class="pl-k">=</span><span class="pl-s"><span class="pl-pds">"</span>https://google.github.io/traceur-compiler/src/bootstrap.js<span
                class="pl-pds">"</span></span><span class="pl-k">&gt;&lt;</span><span class="pl-k">/</span>script<span
                class="pl-k">&gt;</span>
<span class="pl-k">&lt;</span>script<span class="pl-k">&gt;</span>
<span class="pl-smi">$traceurRuntime</span>.<span class="pl-smi">ModuleStore</span>.<span class="pl-en">getAnonymousModule</span>(<span
                class="pl-k">function</span>() {
  <span class="pl-s"><span class="pl-pds">"</span>use strict<span class="pl-pds">"</span></span>;

  <span class="pl-k">var</span> <span class="pl-en">Calc</span> <span class="pl-k">=</span> <span
                class="pl-k">function</span> <span class="pl-en">Calc</span>() {
    <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-s"><span class="pl-pds">'</span>Calc constructor<span
                class="pl-pds">'</span></span>);
  };

  (<span class="pl-smi">$traceurRuntime</span>.<span class="pl-smi">createClass</span>)(Calc, {<span
                class="pl-en">add</span><span class="pl-k">:</span> <span class="pl-k">function</span>(<span
                class="pl-smi">a</span>, <span class="pl-smi">b</span>) {
    <span class="pl-k">return</span> a <span class="pl-k">+</span> b;
  }}, {});

  <span class="pl-k">var</span> c <span class="pl-k">=</span> <span class="pl-k">new</span> <span
                class="pl-en">Calc</span>();
  <span class="pl-en">console</span>.<span class="pl-c1">log</span>(<span class="pl-smi">c</span>.<span class="pl-c1">add</span>(<span
                class="pl-c1">4</span>, <span class="pl-c1">5</span>));
  <span class="pl-k">return</span> {};
});
<span class="pl-k">&lt;</span><span class="pl-k">/</span>script<span class="pl-k">&gt;</span></pre>
    </div>
    <h3><a href="#命令行转换"  class="anchor" id="user-content-命令行转换">
        
    </a>命令行转换
    </h3>
    <p>作为命令行工具使用时，Traceur 是一个 Node 的模块，首先需要用 npm 安装。</p>
    <div class="highlight highlight-source-shell">
        <pre>$ npm install -g traceur</pre>
    </div>
    <p>安装成功后，就可以在命令行下使用 Traceur 了。</p>
    <p>Traceur 直接运行 ES6 脚本文件，会在标准输出显示运行结果，以前面的<code>calc.js</code>为例。</p>
    <div class="highlight highlight-source-shell"><pre>$ traceur calc.js
Calc constructor
9</pre>
    </div>
    <p>如果要将 ES6 脚本转为 ES5 保存，要采用下面的写法。</p>
    <div class="highlight highlight-source-shell">
        <pre>$ traceur --script calc.es6.js --out calc.es5.js</pre>
    </div>
    <p>上面代码的<code>--script</code>选项表示指定输入文件，<code>--out</code>选项表示指定输出文件。</p>
    <p>为了防止有些特性编译不成功，最好加上<code>--experimental</code>选项。</p>
    <div class="highlight highlight-source-shell">
        <pre>$ traceur --script calc.es6.js --out calc.es5.js --experimental</pre>
    </div>
    <p>命令行下转换生成的文件，就可以直接放到浏览器中运行。</p>
    <h3><a href="#node-环境的用法"  class="anchor" id="user-content-node-环境的用法">
        
    </a>Node 环境的用法
    </h3>
    <p>Traceur 的 Node 用法如下（假定已安装<code>traceur</code>模块）。</p>
    <div class="highlight highlight-source-js"><pre><span class="pl-k">var</span> traceur <span
            class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">'</span>traceur<span
            class="pl-pds">'</span></span>);
<span class="pl-k">var</span> fs <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span
                class="pl-pds">'</span>fs<span class="pl-pds">'</span></span>);

<span class="pl-c"><span class="pl-c">//</span> 将 ES6 脚本转为字符串</span>
<span class="pl-k">var</span> contents <span class="pl-k">=</span> <span class="pl-smi">fs</span>.<span class="pl-en">readFileSync</span>(<span
                class="pl-s"><span class="pl-pds">'</span>es6-file.js<span class="pl-pds">'</span></span>).<span
                class="pl-c1">toString</span>();

<span class="pl-k">var</span> result <span class="pl-k">=</span> <span class="pl-smi">traceur</span>.<span
                class="pl-c1">compile</span>(contents, {
  filename<span class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">'</span>es6-file.js<span
                class="pl-pds">'</span></span>,
  sourceMap<span class="pl-k">:</span> <span class="pl-c1">true</span>,
  <span class="pl-c"><span class="pl-c">//</span> 其他设置</span>
  modules<span class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">'</span>commonjs<span
                class="pl-pds">'</span></span>
});

<span class="pl-k">if</span> (<span class="pl-smi">result</span>.<span class="pl-smi">error</span>)
  <span class="pl-k">throw</span> <span class="pl-smi">result</span>.<span class="pl-smi">error</span>;

<span class="pl-c"><span class="pl-c">//</span> result 对象的 js 属性就是转换后的 ES5 代码</span>
<span class="pl-smi">fs</span>.<span class="pl-en">writeFileSync</span>(<span class="pl-s"><span class="pl-pds">'</span>out.js<span
                class="pl-pds">'</span></span>, <span class="pl-smi">result</span>.<span class="pl-smi">js</span>);
<span class="pl-c"><span class="pl-c">//</span> sourceMap 属性对应 map 文件</span>
<span class="pl-smi">fs</span>.<span class="pl-en">writeFileSync</span>(<span class="pl-s"><span class="pl-pds">'</span>out.js.map<span
                class="pl-pds">'</span></span>, <span class="pl-smi">result</span>.<span class="pl-smi">sourceMap</span>);</pre>
    </div>
</div>
</body>
</html>
